#include "CBL_State.h"
#include "CBL_Debug.h"

#include <algorithm>

CB_NAMESPACE_START

	// -----------------------------------------------------------------------------------------------------------------
	//	IState
	// -----------------------------------------------------------------------------------------------------------------

	void IState::AddConnection(CConnection& _rConnection)
	{
		const CConnectionList::iterator EndIter = m_Connections.end();
		for (	CConnectionList::iterator Iter = m_Connections.begin();
				Iter != EndIter;
				++Iter)
		{
			if (Debug::Verify(	**Iter == _rConnection, 
								"Tried to add a duplicate connection.\nConnection will not be added."))
			{
				return;
			}
		}
			
		m_Connections.push_back(&_rConnection);
	}

	// -----------------------------------------------------------------------------------------------------------------

	void IState::RemoveConnection(const IState& _rState)
	{
		const CConnectionList::iterator EndIter = m_Connections.end();
		for (	CConnectionList::iterator Iter = m_Connections.begin();
				Iter != EndIter;
				++Iter)
		{
			if (**Iter == _rState)
			{
				m_Connections.erase(Iter);
				break;
			}
		}
	}

	// -----------------------------------------------------------------------------------------------------------------

	CConnection* IState::GetConnection(const IState& _rNextState)
	{
		const CConnectionList::iterator EndIter = m_Connections.end();
		for (	CConnectionList::iterator Iter = m_Connections.begin();
				Iter != EndIter;
				++Iter)
		{
			if (**Iter == _rNextState)
			{
				return *Iter;
			}
		}
		
		return NULL;
	}

	// -----------------------------------------------------------------------------------------------------------------
	//	CStateMachine
	// -----------------------------------------------------------------------------------------------------------------

	IState* CStateMachine::Execute()
	{
		if (m_pNextState != NULL)
		{
			CConnection* pConnection = m_pActiveState->GetConnection(*m_pNextState);
			
			if (Debug::Verify(	pConnection != NULL, 
								"Unsupported state change. Change failed."))
			{
				m_pActiveState->OnLeave(*m_pNextState);
				pConnection->Execute();
				m_pNextState->OnEnter(*m_pActiveState);
				
				m_pActiveState = m_pNextState;
			}
			
			m_pNextState = NULL;
		}
		
		IState* pNextState = m_pActiveState->Execute();
		
		if (pNextState)
			ChangeState(*pNextState);
		
		return NULL;
	}

CB_NAMESPACE_END